/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
 * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
 * to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

package com.swak.monitor.dubbo.web;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import org.springframework.beans.factory.annotation.Autowired;

import com.swak.annotation.Delete;
import com.swak.annotation.Get;
import com.swak.annotation.Post;
import com.swak.annotation.Put;
import com.swak.annotation.RestApi;
import com.swak.monitor.dubbo.exception.ParamValidationException;
import com.swak.monitor.dubbo.exception.ResourceNotFoundException;
import com.swak.monitor.dubbo.model.dto.ConfigDTO;
import com.swak.monitor.dubbo.service.ManagementService;
import com.swak.monitor.dubbo.service.ProviderService;
import com.swak.monitor.dubbo.utils.Constants;

@RestApi(value = "DubboManagementApi", path = "/api/monitor/:env/manage")
public class ManagementApi {

    @Autowired
    private final ManagementService managementService;
    @Autowired
    private final ProviderService providerService;

    private static Pattern CLASS_NAME_PATTERN =
        Pattern.compile("([a-zA-Z_$][a-zA-Z\\d_$]*\\.)*[a-zA-Z_$][a-zA-Z\\d_$]*");

    @Autowired
    public ManagementApi(ManagementService managementService, ProviderService providerService) {
        this.managementService = managementService;
        this.providerService = providerService;
    }

    @Post("/config")
    public boolean createConfig(ConfigDTO config, String env) {
        managementService.setConfig(config);
        return true;
    }

    @Put("/config/:key")
    public boolean updateConfig(String key, ConfigDTO configDTO, String env) {
        if (key == null) {
            throw new ParamValidationException("Unknown ID!");
        }
        String exitConfig = managementService.getConfig(key);
        if (exitConfig == null) {
            throw new ResourceNotFoundException("Unknown ID!");
        }
        return managementService.updateConfig(configDTO);
    }

    @Get("/config/:key")
    public List<ConfigDTO> getConfig(String key, String env) {
        Set<String> query = new HashSet<>();
        List<ConfigDTO> configDTOs = new ArrayList<>();
        if (key.equals(Constants.ANY_VALUE)) {
            query = providerService.findApplications();
            query.add(Constants.GLOBAL_CONFIG);
        } else {
            query.add(key);
        }
        for (String q : query) {
            String config = managementService.getConfig(q);
            if (config == null) {
                continue;
            }
            ConfigDTO configDTO = new ConfigDTO();
            configDTO.setKey(q);
            configDTO.setConfig(config);
            configDTO.setPath(managementService.getConfigPath(q));
            if (Constants.GLOBAL_CONFIG.equals(q)) {
                configDTO.setScope(Constants.GLOBAL_CONFIG);
            } else if (CLASS_NAME_PATTERN.matcher(q).matches()) {
                configDTO.setScope(Constants.SERVICE);
            } else {
                configDTO.setScope(Constants.APPLICATION);
            }
            configDTOs.add(configDTO);
        }
        return configDTOs;
    }

    @Delete("/config/:key")
    public boolean deleteConfig(String key, String env) {
        return managementService.deleteConfig(key);
    }
}
